#ifndef XGE_XWORKER_DOUBLE_QUEUE_H_
#define XGE_XWORKER_DOUBLE_QUEUE_H_
#include "xge_common_config.h"
#include "xworker_queue.h"
#include "xassert.h"
#include "xsync.h"


namespace xge{
namespace xge_internal{

  // A double queue implementation
  // this queue will be not able to kill or do anything about the task has been push into the queue
  class WorkerDoubleQueue : public WorkerQueue  {
  public:
    // Push 
    virtual bool PushTask( const TaskPtr& ptr );
    virtual bool TryPushTask( const TaskPtr& ptr );
    typedef WorkerQueue::TaskPtrList TaskPtrList;
    virtual size_t PushTask( TaskPtrList* container );
    // Wait
    virtual bool WaitWhenEmpty();
    virtual bool WaitWhenRelease();
    virtual const TripleResult WaitWhenEmpty( int ms );
    virtual const TripleResult WaitWhenRelease( int ms );
    // Post
    inline virtual void PostQuitSoon();
    inline virtual void PostQuitWhenEmpty();
    // Loop
    virtual int Loop();
    // Ctor
    inline WorkerDoubleQueue() ;
  public:
    // back queue size 
    // dangerous
    size_t size() const {
      return front_size_ + back_size_;
    }

    bool empty() const {
      return empty_;
    }

  private:
    // swap the queue
    inline void SwapQueue();
    // wake up the back thread
    inline void WakeUp();
    // Execute all the queue 
    bool ProcessQuitOption( TaskPtrList::iterator& begin , TaskPtrList::iterator& end );
  private:
    // two queue
    TaskPtrList queue1_ , queue2_;
    // front and back queue ptr
    TaskPtrList * volatile front_queue_ , * volatile back_queue_;
    // synchronization lock
    FastLock queue_sync_lock_;
    // sleep lock
    WaitableEvent sleep_lock_;
    enum {
      RUNNING ,
      QUIT_SOON , 
      QUIT_EMPTY 
    };
    // quit option for this queue
    int quit_option_;
    // empty tag for PostQuitWhenEmpty
    bool empty_;
    // size of the queue
    size_t back_size_;
    size_t front_size_;
  };

  inline WorkerDoubleQueue::WorkerDoubleQueue() : 
    front_queue_( &queue1_ ) , 
    back_queue_( &queue2_ ) , 
    quit_option_(RUNNING) ,
    empty_(false) ,
    sleep_lock_(false),
    back_size_(0),
    front_size_(0),
    WorkerQueue( WorkerQueue::QUEUE_TYPE_DOUBLE_QUEUE , REMOTE_BINDING ) {}

  inline void WorkerDoubleQueue::PostQuitSoon() {
    set_status(WorkerQueue::STATUS_LOCKING);
    quit_option_ = (QUIT_SOON);
    WakeUp();
  }

  inline void WorkerDoubleQueue::PostQuitWhenEmpty() {
    set_status(WorkerQueue::STATUS_LOCKING);
    quit_option_ = (QUIT_EMPTY);
    WakeUp();
  }

  inline void WorkerDoubleQueue::SwapQueue() {
    AutoLock<FastLock> l(queue_sync_lock_);
    std::swap( front_queue_ , back_queue_ );
    front_size_ = back_size_;
    back_size_ = 0;
  }

  inline void WorkerDoubleQueue::WakeUp() {
    sleep_lock_.Notify();
  }

}// namespace xge_internal
}// namespace xge


#endif// XGE_XWORKER_DOUBLE_QUEUE_H_